package cn.xd.core.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.xd.common.dto.PageQuery;
import cn.xd.core.converter.Converter;
import cn.xd.core.ddd.entity.BasicEntity;
import cn.xd.core.ddd.value.IdValue;
import cn.xd.core.entity.BasicDBEntity;
import cn.xd.core.mapper.BasicMapper;
import cn.xd.core.response.CollectResult;
import cn.xd.core.response.IntegerResult;
import cn.xd.core.response.ObjectResult;
import cn.xd.core.response.OptionalObjectResult;
import cn.xd.core.service.BasicMpService;
import cn.xd.core.utils.ValueUtils;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author mirzaLin
 * @data 2023/11/14
 * @description IBasicService实现
 **/
public abstract class BasicMpServiceImpl<M extends BasicMapper<T>, T extends BasicDBEntity>
        extends MppServiceImpl<M, T> implements BasicMpService<T> {

    @Override
    public boolean save(T entity) {
        //新增没有id，则自己设置id
        if (ObjUtil.isEmpty(entity.getId())) {
            entity.setId(IdUtil.getSnowflakeNextId());
        }
        return SqlHelper.retBool(this.getBaseMapper().insert(entity));
    }

    @Override
    public <R extends BasicEntity> OptionalObjectResult<T> saveResult(R entity, Converter<R, T> converter) {
        T data = converter.toData(entity);
        if (ValueUtils.isNull(entity.getId())) {
            Long id = IdUtil.getSnowflakeNextId();
            data.setId(id);
        }

        return OptionalObjectResult.of(this.baseMapper.insert(data), data);
    }

    @Override
    public OptionalObjectResult<T> saveResult(T entity) {
        if (ObjUtil.isEmpty(entity.getId())) {
            Long id = IdUtil.getSnowflakeNextId();
            entity.setId(id);
        }
        return OptionalObjectResult.of(this.baseMapper.insert(entity), entity);
    }


    /**
     * description:批量新增，一条sql插入所有的sql语句
     *
     * @param batchList 新增数据的集合对象
     * @return 是否执行成功
     */
    @Override
    public IntegerResult saveAllBatchResult(Collection<T> batchList) {
        return IntegerResult.of(baseMapper.insertAllBatch(batchList));
    }


    @Override
    public <R extends BasicEntity> IntegerResult updateResult(R entity, Converter<R, T> converter) {
        T data = converter.toData(entity);
        return IntegerResult.of(this.baseMapper.updateById(data));
    }

    @Override
    public <R extends BasicEntity> IntegerResult updateNotSelectiveResult(R entity, Converter<R, T> converter) {
        T data = converter.toData(entity);
        return IntegerResult.of(this.baseMapper.updateByIdNotSelective(data));
    }

    @Override
    public IntegerResult updateResult(T entity) {
        return IntegerResult.of(this.baseMapper.updateById(entity));
    }

    @Override
    public IntegerResult updateNotSelectiveResult(T entity) {
        return IntegerResult.of(this.baseMapper.updateByIdNotSelective(entity));
    }

    @Override
    public ObjectResult<T> getResult(Serializable id) {
        return ObjectResult.of(this.baseMapper.selectById(id));
    }

    @Override
    public <R> ObjectResult<R> getResult(Serializable id, Converter<R, T> converter) {
        T t = this.baseMapper.selectById(id);
        return ObjUtil.isEmpty(t) ? ObjectResult.of(null) : ObjectResult.of(converter.fromData(t));
    }

    @Override
    public <R> ObjectResult<R> getResult(IdValue id, Converter<R, T> converter) {
        T t = this.baseMapper.selectById(id.getValue());
        return ObjUtil.isEmpty(t) ? ObjectResult.of(null) : ObjectResult.of(converter.fromData(t));
    }

    @Override
    public ObjectResult<T> getResult(IdValue id) {
        return ObjectResult.of(this.baseMapper.selectById(id.getValue()));
    }

    /**
     * description:重写getOne方法，加上"LIMIT 1"，防止出现异常
     * 不用担心存在多个abstractWrapper.last("LIMIT 1")，默认已经处理，不会出现重复
     *
     * @param wrapper /
     * @return /
     */
    @Override
    public ObjectResult<T> getOneForLimitOneResult(Wrapper<T> wrapper) {
        AbstractWrapper<T, SFunction<T, ?>, ?> abstractWrapper = (AbstractWrapper<T, SFunction<T, ?>, ?>) wrapper;
        abstractWrapper.last("LIMIT 1");
        return ObjectResult.of(this.getOne(abstractWrapper, true));
    }

    /**
     * description:重写getOne方法，加上"LIMIT 1"，防止出现异常
     * 不用担心存在多个abstractWrapper.last("LIMIT 1")，默认已经处理，不会出现重复
     *
     * @param wrapper /
     * @return /
     */
    @Override
    public <R> ObjectResult<R> getOneForLimitOneResult(Wrapper<T> wrapper, Converter<R, T> converter) {
        AbstractWrapper<T, SFunction<T, ?>, ?> abstractWrapper = (AbstractWrapper<T, SFunction<T, ?>, ?>) wrapper;
        abstractWrapper.last("LIMIT 1");
        T one = getOne(abstractWrapper, true);
        return ObjUtil.isEmpty(one) ? ObjectResult.of(null) : ObjectResult.of(converter.fromData(one));
    }

    @Override
    public Page<T> getPage(Wrapper<T> wrapper, PageQuery page) {
        if (wrapper == null) {
            Page<T> pageInfo = new Page<>(page.getPage(), page.getSize());
            return pageInfo.setRecords(new ArrayList<>());
        }
        AbstractWrapper<T, SFunction<T, ?>, ?> abstractWrapper = (AbstractWrapper<T, SFunction<T, ?>, ?>) wrapper;
        Page<T> pageInfo = new Page<>(page.getPage(), page.getSize());
        pageInfo = this.page(pageInfo, abstractWrapper);
        return pageInfo;
    }

    @Override
    public <R> Page<R> getPage(Wrapper<T> wrapper, Converter<R, T> converter, PageQuery page) {
        if (wrapper == null) {
            wrapper = new LambdaQueryWrapper<>();
        }
        Page<T> pageInfo = new Page<>(page.getPage(), page.getSize());
        pageInfo = this.page(pageInfo, wrapper);
        return (Page<R>) pageInfo.convert(converter::fromData);
    }

    @Override
    public <R> CollectResult<R> getList(Wrapper<T> wrapper, Converter<R, T> converter) {
        if (wrapper == null) {
            wrapper = new LambdaQueryWrapper<>();
        }
        List<T> list = this.list(wrapper);
        return CollectResult.of(converter.fromData(list));
    }
}
